package com.quantdo.qtm.linux.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jcraft.jsch.Session;
import com.quantdo.qtm.interfaces.common.QuantdoResponse;
import com.quantdo.qtm.interfaces.common.ResultCodeEnum;
import com.quantdo.qtm.interfaces.linux.pojo.monitor.query.LinuxStatusPointQuery;
import com.quantdo.qtm.linux.dao.LinuxStatusCurrDao;
import com.quantdo.qtm.linux.dao.LinuxStatusHistory;
import com.quantdo.qtm.linux.dao.LinuxStatusPoint;
import com.quantdo.qtm.linux.pojo.model.LinuxStatusCurrDo;
import com.quantdo.qtm.linux.pojo.model.LinuxStatusPointDo;
import com.quantdo.qtm.linux.service.LinuxMonitorScheduledService;
import com.quantdo.qtm.linux.service.LinuxMonitorService;

/**
 * 
 * @author zhouqq
 *
 */
@Service
public class LinuxMonitorServiceImpl implements LinuxMonitorService, LinuxMonitorScheduledService {
    private static final Pattern PA = Pattern.compile("(\\w+)/(\\w+)@(\\d{1,3}(?:\\.\\d{1,3}){3})\\:(\\S+)");

    @Autowired
    private LinuxStatusCurrDao linuxStatusCurrDao;
    @Autowired
    private LinuxStatusHistory linuxStatusHistory;
    @Autowired
    private LinuxStatusPoint linuxStatusPoint;
    
    @Autowired
    private LinuxShellOperate shellOperate; 
    
    @Value("${linuxservers}")
    private String linuxservers;

    public List<LinuxStatusPointDo> selectStatus(LinuxStatusPointQuery statusPointQuery) {
        Calendar beginTime = Calendar.getInstance();
        beginTime.add(Calendar.HOUR_OF_DAY, -24);
        statusPointQuery.setBeginTime(beginTime.getTime());
        return linuxStatusPoint.select(statusPointQuery);
    }
    
    @Override
    public QuantdoResponse<?> selectCpuRate(LinuxStatusPointQuery statusPointQuery) {
        List<LinuxStatusPointDo> statusPointDos = selectStatus(statusPointQuery);
        Map<String, Object> res = new HashMap<String, Object>();
        res.put("xAxis", selectCurrTime(statusPointDos));
        res.put("yAxis", selectItem(statusPointDos, LinuxStatusPointDo::getCpuUsedRate));
        return QuantdoResponse.success(res);
    }

    @Override
    public QuantdoResponse<?> selectMemoryRate(LinuxStatusPointQuery statusPointQuery) {
        List<LinuxStatusPointDo> mysqlStatusPointDos = selectStatus(statusPointQuery);
        Map<String, Object> res = new HashMap<String, Object>();
        res.put("xAxis", selectCurrTime(mysqlStatusPointDos));
        res.put("yAxis", selectItem(mysqlStatusPointDos, LinuxStatusPointDo::getMemoryUsedRate));
        return QuantdoResponse.success(res);
    }

    @Override
    public QuantdoResponse<?> selectDiskRate(LinuxStatusPointQuery statusPointQuery) {
        List<LinuxStatusPointDo> mysqlStatusPointDos = selectStatus(statusPointQuery);
        Map<String, Object> res = new HashMap<String, Object>();
        res.put("xAxis", selectCurrTime(mysqlStatusPointDos));
        res.put("yAxis", selectItem(mysqlStatusPointDos, LinuxStatusPointDo::getDiskUsedRate));
        return QuantdoResponse.success(res);
    }

    @Override
    @Transactional
    public int updateStatus() {
        System.out.println(linuxservers);
        if (Objects.isNull(linuxservers)) return ResultCodeEnum.FAIL.getCode();
        String[] linuxServers = linuxservers.split(";");
        List<LinuxStatusCurrDo> list = new ArrayList<LinuxStatusCurrDo>();
        for (String linuxServer : linuxServers) {
            if (Objects.isNull(linuxServer)) continue;
            Matcher matcher = PA.matcher(linuxServer);
            if(matcher.find()) {
                list.add(linuxOpera(matcher.group(3),matcher.group(1),matcher.group(2),matcher.group(4)));
            }
        }
        saveDate(list);
        return ResultCodeEnum.SUCCESS.getCode();
    }

    /**
     * @param list
     */
    private void saveDate(List<LinuxStatusCurrDo> list) {
        //该处循环次数可控
        for(LinuxStatusCurrDo linuxDo : list) {
            linuxStatusCurrDao.delete(linuxDo);
            linuxStatusCurrDao.insert(linuxDo);
            linuxStatusHistory.insert(linuxDo);
            LinuxStatusPointDo pointDo = new LinuxStatusPointDo();
            pointDo.setCurrTime(linuxDo.getCurrTime());
            pointDo.setCpuUsedRate(100-linuxDo.getCpuFree());
            pointDo.setLinuxServer(linuxDo.getLinuxServer());
            pointDo.setMemoryUsedRate(linuxDo.getMoneryUsed()*100/linuxDo.getMoneryTotal());
            pointDo.setSwapUsedRate(linuxDo.getSwapUsed()*100/linuxDo.getSwapTotal());
            pointDo.setDiskUsedRate(linuxDo.getDiskUsedRate());
            pointDo.setDiskPath(linuxDo.getDiskPath());
            linuxStatusPoint.insert(pointDo);
        }
    }
    
    private LinuxStatusCurrDo linuxOpera(String serverIp, String user, String passwd, String path) {
        Session session = shellOperate.getSession(serverIp, user, passwd);
        String[] res = shellOperate.connection(session, shellOperate.getShell(path));
        if(null != res && null != res[0]) {
            String[] val = res[0].split("\\s+");
            LinuxStatusCurrDo linuxStatusCurrDo = new LinuxStatusCurrDo();
            linuxStatusCurrDo.setCurrTime(new Date());
            linuxStatusCurrDo.setLinuxServer(serverIp);
            linuxStatusCurrDo.setDiskPath(path);
            linuxStatusCurrDo.setMoneryTotal(Integer.parseInt(val[0]));
            linuxStatusCurrDo.setMoneryUsed(Integer.parseInt(val[1]));
            linuxStatusCurrDo.setMoneryFree(Integer.parseInt(val[2]));
            linuxStatusCurrDo.setMoneryCatch(Integer.parseInt(val[3]));
            linuxStatusCurrDo.setMoneryBuffer(Integer.parseInt(val[4]));
            linuxStatusCurrDo.setSwapTotal(Integer.parseInt(val[5]));
            linuxStatusCurrDo.setSwapUsed(Integer.parseInt(val[6]));
            linuxStatusCurrDo.setSwapFree(Integer.parseInt(val[7]));
            linuxStatusCurrDo.setCpuUserUsed(getInteger(val[8]));//
            linuxStatusCurrDo.setCpuSysUsed(getInteger(val[9]));
            linuxStatusCurrDo.setCpuFree(getInteger(val[10]));
            linuxStatusCurrDo.setDiskUsedRate(getInteger(val[12]));//
            linuxStatusCurrDo.setDiskTotal(Integer.parseInt(val[13]));
            linuxStatusCurrDo.setDiskUsed(Integer.parseInt(val[14]));
            return linuxStatusCurrDo;
        }
        return null;
    }

    private Integer getInteger(String val) {
        if(null != val)return new BigDecimal(val.replaceAll("[^0-9\\.]", "")).intValue();
        return null;
    }
    private List<?> selectItem(List<LinuxStatusPointDo> mysqlStatusPointDos, Function<? super LinuxStatusPointDo, ? extends Integer> mapper){
        return mysqlStatusPointDos.stream().map(mapper).collect(Collectors.toList());
    }
    private List<?> selectCurrTime(List<LinuxStatusPointDo> mysqlStatusPointDos){
        return mysqlStatusPointDos.stream().map(LinuxStatusPointDo::getFormatTime).collect(Collectors.toList());
    }
}
